/*
 * ObjectPoint.java
 *
 * Created on December 12, 2007, 11:51 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package editor;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;

/**
 *
 * @author Martin Demin, Eduard Benes
 */
public final class ObjectPoint implements Object {
    
    Point2D start;
    Point2D end;
    private boolean selected;
    int draggedPoint;
    
    private float scaleX;
    private float scaleY;
    private ObjectInfo info;
    
    
    
    /** Creates a new instance of ObjectPolygon */
    public ObjectPoint() {
        start = null;
        end = null;
        selected = false;
        scaleX = 1;
        scaleY = 1;
        draggedPoint = -1;
        
    }

    /**
     * Add point to the object, coordinates are in meters
     */
    public void addPoint(Point2D p) {
        if(start == null)
        {
            start = p;
            return;
        }
        end = p;
    }
    
    /**
     * Redraw this object
     */
    public void draw(Graphics g) {
        
        if(selected) 
            g.setColor(Color.RED);
        else
            g.setColor(Color.WHITE);
        
        if(start != null)
            g.drawRect((int)(start.getX()*scaleX-3), (int)(start.getY()*scaleY-3), 6 , 6);
        if(end != null && start != null)
            g.drawPolygon(getArrow((int)(start.getX()*scaleX), (int)(start.getY()*scaleY), 
                    (int)(end.getX()*scaleX), (int)(end.getY()*scaleY), 10, 5,0.5));
            
            
        
    }

    private void drawArrow(int x1, int y1, int x2, int y2, Graphics g) {
        g.drawPolygon(getArrow(x1, y1, x2, y2, 10, 5,0.5));
    }

    private Polygon getArrow(int x1, int y1, int x2, int y2, int headsize, int difference, double factor) {
        int[] crosslinebase = getArrowHeadLine(x1, y1, x2, y2, headsize);
        int[] headbase = getArrowHeadLine(x1, y1, x2, y2, headsize - difference);
        int[] crossline = getArrowHeadCrossLine(crosslinebase[0], crosslinebase[1], x2, y2, factor);

        Polygon head = new Polygon();

        head.addPoint(headbase[0], headbase[1]);
        head.addPoint(crossline[0], crossline[1]);
        head.addPoint(x2, y2);
        head.addPoint(crossline[2], crossline[3]);
        head.addPoint(headbase[0], headbase[1]);
        head.addPoint(x1, y1);

        return head;
    }

    private int[] getArrowHeadLine(int xsource, int ysource,int xdest,int ydest, int distance) {
        int[] arrowhead = new int[2];
        int headsize = distance;

        double stretchfactor = 0;
        stretchfactor = 1 - (headsize/(Math.sqrt(((xdest-xsource)*(xdest-xsource))+((ydest-ysource)*(ydest-ysource)))));

        arrowhead[0] = (int) (stretchfactor*(xdest-xsource))+xsource;
        arrowhead[1] = (int) (stretchfactor*(ydest-ysource))+ysource;

        return arrowhead;
    }

    private int[] getArrowHeadCrossLine(int x1, int x2, int b1, int b2, double factor) {
        int [] crossline = new int[4];

        int x_dest = (int) (((b1-x1)*factor)+x1);
        int y_dest = (int) (((b2-x2)*factor)+x2);

        crossline[0] = (int) ((x1+x2-y_dest));
        crossline[1] = (int) ((x2+x_dest-x1));
        crossline[2] = crossline[0]+(x1-crossline[0])*2;
        crossline[3] = crossline[1]+(x2-crossline[1])*2;
        return crossline;
    } 
    
    /**
     * Get the type of the object
     */
    public int getType() {
        return 3; // oriented point
    }
    
    /**
     * Set scaling of the object pixel -> meters transformation
     */
    public void setScale(float scaleX, float scaleY) {
        this.scaleX = scaleX;
        this.scaleY = scaleY;
    }
    
    /**
     * Unselect the current object
     */
    public void unselect() {
        selected = false;
    }

    /**
     * If the given point is on the object, the object will be selected
     * @return True if the object has been selected
     */
    public boolean doSelected(int x, int y) {
        int count = 0;
        double d = 0.0;
        
        d = start.distance(x/scaleX, y/scaleY);
        if ( d<= 3)
        {
            selected = true;
            draggedPoint = 0;
            return true;
        }
        if(end != null)
        {
            d = end.distance(x/scaleX, y/scaleY);
            if ( d<= 3)
            {
                selected = true;
                draggedPoint = 1;
                return true;
            }
        }
        draggedPoint = -1;
        return false;
    }

    /**
     * 
     * @return Returns true if this object is selected
     */
    public boolean isSelected() {
        return selected;
    }

    /**
     * Drag the nearby point
     */
    public void doDragged(int x, int y) {
        double d;
    
        if(draggedPoint == -1) {
            d = start.distance(x/scaleX, y/scaleY);
            if ( d<= 3)
            {
                selected = true;
                draggedPoint = 0;
            }
            if(end != null)
            {
                d = end.distance(x/scaleX, y/scaleY);
                if ( d<= 3)
                {
                    selected = true;
                    draggedPoint = 1;
                }
            }
        }

        if(draggedPoint == 0) {
            start.setLocation(x/scaleX, y/scaleY);
        }
        
        if(draggedPoint == 1) {
            end.setLocation(x/scaleX, y/scaleY);
        }
    
    }

     /**
     * Called when the mouse is released and this object was selected
     */
    public void doReleased() {
        draggedPoint = -1;
    }


    /**
     * Selected ?
     * @return Returns true if this object is complete and can be added into scene
     */
    public boolean isComplete() {
        if(start != null || end != null) return true;
        return false;
    }

    /**
     * Set this object as selected
     */
    public void select() {
        selected = true;
    }

    /**
     * Adds a point into the object
     * @param i x-axis in pixels of the point to be added
     * @param i0 y-axis in pixels of the point to be added
     */
    public void addPoint(int i, int i0) {
        addPoint(new Point2D.Double(i/scaleX, i0/scaleY));
    }

    /**
     * Finds out if a point can be added to the object
     * @return true if can add, false otherwise
     */
    public boolean canAdd() {
        if(start == null || end == null) return true;
        return false;
        
    }

    /**
     * Sets ObjectInfo class
     * @param i ObjectInfo class
     */
    public void setInfo(ObjectInfo i) {
        info = i;
    }

    /**
     * Get info
     * @return Returns reference to ObjectInfo class
     */
    public ObjectInfo getInfo() {
        return info;
    }
    
    //MDSYS.SDO_GEOMETRY(2001, NULL, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1,1,1, 3,1,0), 
    //MDSYS.SDO_ORDINATE_ARRAY(0,0, 0.5,0.5)),
    
    /**
     * Returns String with SDO_GEOM syntax to be inserted into DB
     * @return String with SDO syntax
     */
    public String getGeom() {
       String s;
        if(end != null)
        {
            s = "MDSYS.SDO_GEOMETRY(2001, NULL, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1,1,1, 3,1,1),MDSYS.SDO_ORDINATE_ARRAY(";

            s += String.valueOf(start.getX());
            s+=',';
            s += String.valueOf(start.getY());
            s+=',';
            s += String.valueOf(end.getX());
            s+=',';
            s += String.valueOf(end.getY());

            s+="))";
        
        }
        else
        { //MDSYS.SDO_GEOMETRY(2001, NULL, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1,1,1),
            //MDSYS.SDO_ORDINATE_ARRAY(15,51))),
            s = "MDSYS.SDO_GEOMETRY(2001, NULL, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1,1,1),MDSYS.SDO_ORDINATE_ARRAY(";

            s += String.valueOf(start.getX());
            s+=',';
            s += String.valueOf(start.getY());

            s+="))";
            
        }
        return s;
    }    
}
